package Model;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

/** 
 *  L'élément 'line' définit un segment de droite qui commence à un point et finit à un autre.
 *  
 *  @author Kilian Cousein et Benjamin Tardieu
 */
public class Ligne extends Motif 
{
//======================================================================//
//============================ Variables ===============================//
//======================================================================//
	
	private int x2; // coordonnées de l'axe des abscisses du deuxième point
	private int y2; // coordonnées de l'axe des ordonnées du deuxième point

	
//======================================================================//
//========================== Constructeurs =============================//
//======================================================================//
	
	/**
	 * Crée une nouvelle instance de <i>Ligne</i> par défaut.
	 */
	public Ligne()
	{
		this.largeurBordure = 1;
	}
	
	
	/**
	 * Crée une nouvelle instance de <i>Ligne</i> qui sera un clone de <i>motif</i>.
	 * 
	 * @param motif Motif
	 */
	public Ligne(Motif motif)
	{	
		super(motif);
		Ligne m = (Ligne) motif;
		
		this.x2 = m.x2;
		this.y2 = m.y2;
	}
	
	
//======================================================================//
//==================== Écriture méthodes abstraites ====================//
//======================================================================//
	
	@Override
	public void dessinerMotif(Graphics2D g) 
	{
		g.setComposite(java.awt.AlphaComposite.getInstance(java.awt.AlphaComposite.SRC_OVER, this.opacite));	
		g.setColor(couleur);
		g.setStroke(new BasicStroke(this.largeurBordure));
		
		g.drawLine(this.x, this.y, this.x2, this.y2);
		g.setComposite(java.awt.AlphaComposite.getInstance(java.awt.AlphaComposite.SRC_OVER, 1.0f));	
	}

	@Override
	public void dessinerPoignees(Graphics2D g)
	{
	
		
		if(this.x <= this.x2 && this.y <= this.y2)
		{
			g.setStroke(new BasicStroke(1));
			g.setColor(Color.white);
			g.fillRect(this.x, this.y, HANDLE_SIZE, HANDLE_SIZE); // left top
			g.fillRect(this.x2 - HANDLE_SIZE, this.y2 - HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE); // right top
			g.setColor(Color.gray);
			g.drawRect(this.x, this.y, HANDLE_SIZE, HANDLE_SIZE); // left top
			g.drawRect(this.x2 - HANDLE_SIZE, this.y2 - HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE); // right top
		}
		else if(this.x >= this.x2 && this.y >= this.y2)
		{
			g.setStroke(new BasicStroke(1));
			g.setColor(Color.white);
			g.fillRect(this.x - HANDLE_SIZE, this.y - HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE); // left top
			g.fillRect(this.x2, this.y2, HANDLE_SIZE, HANDLE_SIZE); // right top
			g.setColor(Color.gray);
			g.drawRect(this.x - HANDLE_SIZE, this.y - HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE); // left top
			g.drawRect(this.x2, this.y2, HANDLE_SIZE, HANDLE_SIZE); // right top
		}
		else if(this.x >= this.x2 && this.y <= this.y2)
		{
			g.setStroke(new BasicStroke(1));
			g.setColor(Color.white);
			g.fillRect(this.x - HANDLE_SIZE, this.y, HANDLE_SIZE, HANDLE_SIZE); // left top
			g.fillRect(this.x2, this.y2 - HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE); // right top
			g.setColor(Color.gray);
			g.drawRect(this.x - HANDLE_SIZE, this.y, HANDLE_SIZE, HANDLE_SIZE); // left top
			g.drawRect(this.x2, this.y2 - HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE); // right top
		}
		else if(this.x <= this.x2 && this.y >= this.y2)
		{
			g.setStroke(new BasicStroke(1));
			g.setColor(Color.white);
			g.fillRect(this.x, this.y - HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE); // left top
			g.fillRect(this.x2 - HANDLE_SIZE, this.y2, HANDLE_SIZE, HANDLE_SIZE); // right top
			g.setColor(Color.gray);
			g.drawRect(this.x, this.y - HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE); // left top
			g.drawRect(this.x2 - HANDLE_SIZE, this.y2, HANDLE_SIZE, HANDLE_SIZE); // right top
		}
	}
	
	
	@Override
	public void deplacer(int x, int y)
    {    	
    	this.x += x;
    	this.y += y;
    	this.x2 += x;
    	this.y2 += y;
    }
	
	
	@Override
	public void redimensionner(int x1, int x2, int y1, int y2)
    {
		switch(this.poigneeSelectionne)
		{
			case Motif.AUCUNE_POIGNEE : 
				this.x += x1; 
				this.y += y1; 
				break;
			case Motif.GAUCHE_HAUT_POIGNEE : 
				this.x = x1; 
				this.y = y1; 
				break;
			case Motif.DROITE_HAUT_POIGNEE :
				this.x2 = x1; 
				this.y2 = y1; 
				break;
			default : 
				break;	
		}
    }
	
	
	@Override
	public boolean contient(Point point)
	{		
		if(this.x <= this.x2 && this.y <= this.y2)
			return ((point.x >= this.x) && (point.y >= this.y) && (point.x <= this.x2) && (point.y <= this.y2));
		else if(this.x >= this.x2 && this.y >= this.y2)
			return ((point.x <= this.x) && (point.y<= this.y) && (point.x >=this.x2) && (point.y >=this.y2));
		else if(this.x <= this.x2 && this.y >= this.y2)
			return ((point.x >= this.x) && (point.y<= this.y) && (point.x <=this.x2) && (point.y >=this.y2));
		else if(this.x >= this.x2 && this.y <= this.y2)
			return ((point.x <= this.x) && (point.y>= this.y) && (point.x >=this.x2) && (point.y <=this.y2));
		else
			return false;
	} 
	 
	
	@Override
	public void faireCorrespondre(int x1, int y1, int x2, int y2) 
	{
		this.x = x1;
		this.y = y1;
		this.x2 = x2;
		this.y2 = y2;
	}
	 
	
	@Override
	public void findHandles(Point point)
	{
		this.poigneeSelectionne = getHandles(point.x, point.y);
	}
	
	
	@Override
	public Element enregistrer(Document doc)
	{
		Element ligne = doc.createElement("line");
		ligne.setAttribute("x1", ""+this.x);
		ligne.setAttribute("y1", ""+this.y);
		ligne.setAttribute("x2", ""+this.x2);
		ligne.setAttribute("y2", ""+this.y2);
		ligne.setAttribute("stroke-width", ""+this.largeurBordure);
		
		if(this.couleur != null)
			ligne.setAttribute("stroke", "rgb("+this.couleur.getRed()+","+this.couleur.getGreen()+","+this.couleur.getBlue()+")");
		
		
		if(this.opacite < 1.0f)
		{
			ligne.setAttribute("opacity", ""+this.opacite);
		}
		
		return ligne;
	}
	
	
	@Override
	public void ouvrir(Node node)
	{
		Node attribut;
		
		for(int j = 0; j < node.getAttributes().getLength(); j++)
		{
			attribut = node.getAttributes().item(j);
			
			if(attribut.getNodeName() == "x1")
				this.x = Integer.valueOf(attribut.getNodeValue());
			else if(attribut.getNodeName() == "y1")
				this.y = Integer.valueOf(attribut.getNodeValue());
			else if(attribut.getNodeName() == "x2")
				this.x2 = Integer.valueOf(attribut.getNodeValue());
			else if(attribut.getNodeName() == "y2")
				this.y2 = Integer.valueOf(attribut.getNodeValue());
			else if(attribut.getNodeName() == "stroke-width")
				this.largeurBordure = Integer.valueOf(attribut.getNodeValue());
			else if(attribut.getNodeName() == "stroke")
				this.couleur = this.convertitStringCouleur(attribut.getNodeValue());
			else if(attribut.getNodeName() == "opacity")
			{
				this.opacite = Float.valueOf(attribut.getNodeValue());
				this.opaciteBordure = Float.valueOf(attribut.getNodeValue());
			}
			else if(attribut.getNodeName() == "stroke-opacity")
				this.opaciteBordure = Float.valueOf(attribut.getNodeValue());
		}
	}
	
	
	@Override
 	public int getHandles(int x, int y) 
	{
		if(this.x <= this.x2 && this.y <= this.y2)
		{
			if ((x >= this.x) && (y >= this.y) && (x <= this.x + HANDLE_SIZE) && (y <= this.y + HANDLE_SIZE)) 
				return GAUCHE_HAUT_POIGNEE;
			else if ((x >= this.x2 - HANDLE_SIZE) && (y >= this.y2 - HANDLE_SIZE) && (x <= this.x2) && (y <= this.y2)) 
				return DROITE_HAUT_POIGNEE;
		}
		else if(this.x >= this.x2 && this.y >= this.y2)
		{
			if ((x <= this.x) && (y <= this.y) && (x >= this.x - HANDLE_SIZE) && (y >= this.y - HANDLE_SIZE)) 
				return GAUCHE_HAUT_POIGNEE;
			else if ((x >= this.x2) && (y >= this.y2) && (x <= this.x2 + HANDLE_SIZE) && (y <= this.y2 + HANDLE_SIZE)) 
				return DROITE_HAUT_POIGNEE;
		}
		else if(this.x >= this.x2 && this.y <= this.y2)
		{
			if ((x <= this.x) && (y >= this.y) && (x >= this.x - HANDLE_SIZE) && (y <= this.y + HANDLE_SIZE)) 
				return GAUCHE_HAUT_POIGNEE;
			else if ((x >= this.x2) && (y >= this.y2 - HANDLE_SIZE) && (x <= this.x2 + HANDLE_SIZE) && (y <= this.y2)) 
				return DROITE_HAUT_POIGNEE;
		}
		else if(this.x <= this.x2 && this.y >= this.y2)
		{
			if ((x >= this.x) && (y <= this.y) && (x <= this.x + HANDLE_SIZE) && (y >= this.y - HANDLE_SIZE)) 
				return GAUCHE_HAUT_POIGNEE;
			else if ((x >= this.x2 - HANDLE_SIZE) && (y >= this.y2) && (x <= this.x2) && (y <= this.y2 + HANDLE_SIZE)) 
				return DROITE_HAUT_POIGNEE;
		}
		
		return AUCUNE_POIGNEE;
	}

	
	@Override
	public Motif nouvelleInstance() 
	{
		Ligne ligne = new Ligne();
		ligne.setCouleur(couleur);
		ligne.setCouleurBordure(this.couleurBordure);
		
		return ligne;
	}

	
	@Override
	public Motif clone()
	{
		return new Ligne(this);
	}
	
//======================================================================//
//============================= Méthodes ===============================//
//======================================================================// 	
	
	@Override
	public boolean equals(Object o)
 	{
		if(this.getClass() == o.getClass())
		{
			Ligne ligne = (Ligne) o;
			boolean egale = true;
			
			egale &= this.x2 == ligne.x2;
			egale &= this.y2 == ligne.y2;
			
	 		return super.equals(ligne) && egale;
		}
		else
			return false;
 	}
	
	
	@Override
	public String toString()
	{
		return super.toString()+"\nx2: "+this.x2+"\ny2: "+this.y2;
	}
	
	
//======================================================================//
//========================= Getters et Setters =========================//
//======================================================================//	
	
 	/**
	 * Retourne les coordonnées de l'abscisses du premier point de la ligne.
	 * 
	 * @return Les coordonnées x du premier point de la ligne.
	 */
	public int getX1()
	{
		return x;
	}
	

	/**
	 * Cette méthode permet de modifier les coordonnées de l'abscisse du premier point de la ligne.
	 * 
	 * @param x1 Nouvelle valeur des coordonnées de l'abscisse du premier point de la ligne.
	 */
	public void setX1(int x1)
	{
		this.x = x1;
	}
	

	/**
	 * Retourne l'ordonnée du premier point de la ligne.
	 * 
	 * @return Les coordonnées y du premier point de la ligne.
	 */
	public int getY1()
	{
		return y;
	}
	

	/**
	 * Cette méthode permet de modifier les coordonnées de l'ordonnée du premier point de la ligne.
	 * 
	 * @param y1 Nouvelle valeur des coordonnées de l'ordonnée du premier point de la ligne.
	 */
	public void setY1(int y1)
	{
		this.y = y1;
	}
	

	/**
	 * Retourne les coordonnées de l'abscisse du deuxième point de la ligne.
	 * 
	 * @return Les coordonnées x du deuxième point de la ligne.
	 */
	public int getX2()
	{
		return x2;
	}
	

	/**
	 * Cette méthode permet de modifier les coordonnées de l'abscisse du deuxième point de la ligne.
	 * 
	 * @param x2 Nouvelle valeur des coordonnées de l'abscisse du deuxième point de la ligne.
	 */
	public void setX2(int x2)
	{
		this.x2 = x2;
	}
	

	/**
	 * Retourne les coordonnées des ordonnées du deuxième point de la ligne.
	 * 
	 * @return Les coordonnées y du deuxième point de la ligne.
	 */
	public int getY2()
	{
		return y2;
	}
	

	/**
	 * Cette méthode permet de modifier les coordonnées de l'ordonnée du deuxième point de la ligne.
	 * 
	 * @param y2 Nouvelle valeur des coordonnées de l'abscisse du premier point de la ligne.
	 */
	public void setY2(int y2)
	{
		this.y2 = y2;
	}
	

	/**
	 * Retourne la largeur de la ligne.
	 * 
	 * @return La largeur de la ligne.
	 */
	public int getLargeurLigne()
	{
		return largeurBordure;
	}

	
	/**
	 * Cette méthode permet de modifier la largeur de la ligne.
	 * 
	 * @param largeurLigne Nouvelle valeur de la largeur de la ligne.
	 */
	public void setLargeurLigne(int largeurLigne)
	{
		this.largeurBordure = largeurLigne;
	}
}
